class TaxCalculator:
                   # 税级             税率       速算扣除数
    old_tax_table = {1500:          [0.03,      0],
                     4500:          [0.1,       105],
                     9000:          [0.2,       555],
                     35000:         [0.25,      1005],
                     55000:         [0.30,      2755],
                     80000:         [0.35,      5505],
                     9999999999:    [0.45,      13505]}
    new_tax_table = {3000:          [0.03,      0],
                     12000:         [0.1,       210],
                     25000:         [0.2,       1410],
                     35000:         [0.25,      2660],
                     55000:         [0.30,      4410],
                     80000:         [0.35,      5505],
                     999999999:     [0.45,      15160]}
    # 速算扣除数 = 上一级速算扣除数 + 上一税级 * (该级税率 - 上一级税率)
    # TODO correct this value
    base_min = 0

    base_max = 23118

    def __init__(self,
                monthly_income,
                month_sum,
                new_or_old=True,
                free_tax_sum=3500,
                year_old=35,
                base_min=0,
                base_max=23118):
        if new_or_old:
            self.tax_table = self.new_tax_table
        else:
            self.tax_table = self.old_tax_table
        if year_old <= 0:
            raise Exception("You age must be larger than zero!")
        self.year_old = year_old
        if month_sum < 12:
            raise Exception("month_sum must be larger than or equal to 12")
        self.month_sum = month_sum
        if monthly_income <= 0:
            raise Exception("month_sum must be large than 0")
        # 扣除五险一金之前的月薪总额
        self.monthly_salary_income = monthly_income
        if free_tax_sum <= 0:
            raise Exception("Free tax sum must be larger than 0")
        # 月免征税额
        self.free_tax_sum = free_tax_sum
        # 养老保险
        self.monthly_retirement_fund = 0
        # 每月应缴公积金
        self.monthly_accumulation_fund = 0
        # 实际每月公积金收入
        self.monthly_accumulation_fund_income = 0
        # 医疗保险
        self.monthly_medical_insurance = 0
        # 医疗保险打入医保卡种
        self.monthly_medical_income = 0
        # 失业保险
        self.monthly_unemployment_insurance = 0
        # 每月应缴税额
        self.monthly_tax = 0
        # 扣除五险一金后应税收入
        self.monthly_taxable_income = 0
        # 年终奖应缴税额
        self.year_bonus_tax = 0
        # 月实际薪水收入，工资卡入账的金额
        self.monthly_actual_salary_income = 0
        # 月实际收入
        self.monthly_actual_income = 0
        # 年终奖税后收入
        self.year_bonus_actual_income = 0
        # 总的年收入
        self.year_actual_income = 0
        # 年终奖税前收入
        self.year_bonus = 0
        # 年纳税总额
        self.year_tax = 0

    def calculate(self):
        self.year_bonus = (self.month_sum - 12) * self.monthly_salary_income
        # 存缴基数
        base = self.monthly_salary_income
        if base > self.base_max:
            base = self.base_max
        elif base < self.base_min:
            base = self.base_min
        # 公积金扣除12%
        self.monthly_accumulation_fund = base * 0.12
        # 公积金收入，公司+个人
        self.monthly_accumulation_fund_income = self.monthly_accumulation_fund * 2;
        # 养老保险扣除8%
        self.monthly_retirement_fund = base * 0.08
        # 医疗保险 = 2%+3元大病统筹
        medical_insurance_ratio = 0.02
        self.monthly_medical_insurance = base * medical_insurance_ratio + 3
        # 医疗存折中的收入为base * (个人比例 + 公司比例)
        if self.year_old <= 35:
            medical_insurance_ratio += 0.008
        elif self.year_old > 35 and self.year_old <= 44:
            medical_insurance_ratio += 0.01
        else:
            medical_insurance_ratio += 0.02
        # 医保存折中的收入
        self.monthly_medical_income = base * medical_insurance_ratio;
        # 失业保险扣除0.2%
        self.monthly_unemployment_insurance = base * 0.002
        # 月收入应税额
        self.monthly_taxable_income = self.monthly_salary_income - self.monthly_accumulation_fund - self.monthly_medical_insurance \
                                      - self.monthly_retirement_fund - self.monthly_unemployment_insurance

        taxable_sum = self.monthly_taxable_income - self.free_tax_sum
        if taxable_sum < 0:
            taxable_sum = 0
        # 计算个税
        for (tax_level, tax_item) in self.tax_table.items():
            if taxable_sum <= tax_level:
                self.monthly_tax = taxable_sum * tax_item[0] - tax_item[1]
                break

        # 实际薪资收入
        self.monthly_actual_salary_income = self.monthly_taxable_income - self.monthly_tax
        # 实际月收入 = 实际薪资收入 + 公积金收入 + 医保收入
        self.monthly_actual_income = self.monthly_actual_salary_income + self.monthly_medical_income + self.monthly_accumulation_fund_income

        # 年终奖
        ## 如果月应税收入不足最低缴税应税额，则年终奖需要减去(最低应税额 - 时机月应税额)
        taxable_year_bonus = self.year_bonus
        if self.monthly_taxable_income < self.free_tax_sum:
            taxable_year_bonus -= (self.free_tax_sum - self.monthly_taxable_income)
        if taxable_year_bonus < 0:
            taxable_year_bonus = 0
        # 应税年终奖/12后在个税表中找到缴税比例和扣除数
        monthly_bonus = taxable_year_bonus / 12
        for (tax_level, tax_item) in self.tax_table.items():
            if monthly_bonus <= tax_level:
                self.year_bonus_tax = taxable_year_bonus * tax_item[0] - tax_item[1]
                break
        self.year_bonus_actual_income = self.year_bonus - self.year_bonus_tax

        # 年收入
        self.year_actual_income = self.year_bonus_actual_income + self.monthly_actual_income * 12

        # 年纳税
        self.year_tax = self.year_bonus_tax + self.monthly_tax * 12

    def output(self):
        output_format = """
Monthly:
Salary:                 %.2f
Medical insurance:      %.2f
Retirement fund:        %.2f
Accumulation fund:      %.2f
Unemployment insurance: %.2f
Tax:                    %.2f
Actual salary income:   %.2f
Monthly total income:   %.2f

Bouns:
Bouns sum:              %.2f
Tax:                    %.2f
Actual bonus:           %.2f

Year:
Actual income:          %.2f
Tax:                    %.2f
        """
        print(output_format % (self.monthly_salary_income,
                               self.monthly_medical_insurance,
                               self.monthly_retirement_fund,
                               self.monthly_accumulation_fund,
                               self.monthly_unemployment_insurance,
                               self.monthly_tax,
                               self.monthly_actual_salary_income,
                               self.monthly_actual_income,
                               self.year_bonus,
                               self.year_bonus_tax,
                               self.year_bonus_actual_income,
                               self.year_actual_income,
                               self.year_tax))


if __name__ == '__main__':
    print("New tax action >>>>>>>>>>>>>>>>>")
    calculator = TaxCalculator(38000, 16, True, free_tax_sum=5000)
    calculator.calculate()
    calculator.output()
    print("Old tax action >>>>>>>>>>>>>>>>>")
    calculator = TaxCalculator(38000, 16, False, free_tax_sum=3500)
    calculator.calculate()
    calculator.output()
    # for (tax_level, tax_item) in TaxCalculator.old_tax_table.items():
    #     print("%s : %s" % (str(tax_level), str(tax_item)))
